package iscte.ai.kcgtd;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.provider.CalendarContract.Calendars;
import android.provider.CalendarContract.Events;
import android.provider.CalendarContract.Instances;

public class ProviderCalendar {
	public static final String[] INSTANCE_PROJECTION = new String[] {
		Instances.EVENT_ID,      // 0
		Instances.BEGIN,         // 1
		Instances.TITLE,          // 2
		Instances.END,          // 3
		Instances.END_DAY,          // 4
		Instances.END_MINUTE,          // 5
		Instances.START_DAY,          // 6
		Instances.START_MINUTE,          // 7
		Instances.EVENT_LOCATION         // 8
	};

	// The indices for the projection array above.
	private static final int PROJECTION_BEGIN_INDEX = 1;
	private static final int PROJECTION_TITLE_INDEX = 2;
	private static final int PROJECTION_END_INDEX = 3;
	@SuppressWarnings("unused")
	private static final int PROJECTION_END_DAY_INDEX = 4;
	@SuppressWarnings("unused")
	private static final int PROJECTION_END_MINUTE_INDEX = 5;
	@SuppressWarnings("unused")
	private static final int PROJECTION_START_DAY_INDEX = 6;
	@SuppressWarnings("unused")
	private static final int PROJECTION_START_MINUTE_INDEX = 7;
	private static final int PROJECTION_EVENT_LOCATION = 8;


	private static final int PROJECTION_ID_INDEX = 0;
	@SuppressWarnings("unused")
	private static final int PROJECTION_ACCOUNT_NAME_INDEX = 1;
	@SuppressWarnings("unused")
	private static final int PROJECTION_DISPLAY_NAME_INDEX = 2;
	@SuppressWarnings("unused")
	private static final int PROJECTION_OWNER_ACCOUNT_INDEX = 3;

	public static final String[] EVENT_PROJECTION = new String[] {
		Calendars._ID, // 0
		Calendars.ACCOUNT_NAME, // 1
		Calendars.CALENDAR_DISPLAY_NAME, // 2
		Calendars.OWNER_ACCOUNT // 3
	};

	public static long getCalendarID(Context context, String email){
		long calendarId = 0;


		// Run query
		Cursor cur = null;
		ContentResolver cr = context.getContentResolver();
		Uri uri = Calendars.CONTENT_URI;
		String selection = "((" + Calendars.ACCOUNT_NAME + " = ?) AND ("
				+ Calendars.ACCOUNT_TYPE + " = ?) AND ("
				+ Calendars.OWNER_ACCOUNT + " = ?))";


//		String[] selectionArgs = new String[] { "kcgtd.ai@gmail.com", "com.google", "kcgtd.ai@gmail.com" };
		String[] selectionArgs = new String[] { MainActivity.settings.getEmail(), "com.google", MainActivity.settings.getEmail() };

		// Submit the query and get a Cursor object back.
		cur = cr.query(uri, EVENT_PROJECTION, selection, selectionArgs, null);
		// Use the cursor to step through the returned records
		while (cur.moveToNext()) {

			calendarId = cur.getLong(PROJECTION_ID_INDEX);
		}
		
		return calendarId;
	}

	public static void addTaskToCalendar( Context context, Task task){
		// Para tratar do CalendarID para que nao tenha que ir sempre ao calendario e do caso em 
		// que a hora para para outro dia / mes /ano
		long calendarId = getCalendarID(context, MainActivity.settings.getEmail());

		String title = task.getName();
		String description = task.getDescricao();
		String location = task.getLocation();
		
		long startMillis = 0; 
		long endMillis = 0;     
		
		Calendar beginTime = Calendar.getInstance();
		beginTime.set(task.getTimeStart().getYear(), task.getTimeStart().getMonth(), task.getTimeStart().getMonthDay(), task.getTimeStart().getHour(), task.getTimeStart().getMinute());
		startMillis = beginTime.getTimeInMillis();
		
		Calendar endTime = Calendar.getInstance();
		endTime.set(task.getTimeEnd().getYear(), task.getTimeEnd().getMonth(), task.getTimeEnd().getMonthDay(), task.getTimeEnd().getHour(), task.getTimeEnd().getMinute());
		endMillis = endTime.getTimeInMillis();

		ContentResolver cr = context.getContentResolver();
		ContentValues values = new ContentValues();
		values.put(Events.DTSTART, startMillis);
		values.put(Events.DTEND, endMillis);
		values.put(Events.TITLE, title);
		values.put(Events.DESCRIPTION, description);
		values.put(Events.CALENDAR_ID, calendarId);
		values.put(Events.EVENT_TIMEZONE, "GMT + 1");
		values.put(Events.EVENT_LOCATION, location);
		Uri uri = cr.insert(Events.CONTENT_URI, values);

		// get the event ID that is the last element in the Uri
		Long eventID = Long.parseLong(uri.getLastPathSegment());
		task.setGoogleCalendarID(eventID);
	}

	public static boolean removeFromGoogleCalendar(Context context, Task task){
		Long eventID = task.getGoogleCalendarID();
		ContentResolver cr = context.getContentResolver();
		Uri deleteUri = null;
		deleteUri = ContentUris.withAppendedId(Events.CONTENT_URI, eventID);
		int rows = cr.delete(deleteUri, null, null);
		if(rows !=0)
			return true;
		return false;
	}

	public static boolean updateTaskGoogleCalendar(Context context, Task t){
		t.setTimeStart(t.getTimeStart());
		t.setTimeEnd(t.getTimeEnd());		

		long startMillis = 0; 
		long endMillis = 0;
		
		Calendar beginTime = Calendar.getInstance();
		beginTime.set(t.getTimeStart().getYear(), t.getTimeStart().getMonth(), t.getTimeStart().getMonthDay(), t.getTimeStart().getHour(), t.getTimeStart().getMinute());
		startMillis = beginTime.getTimeInMillis();
		
		Calendar endTime = Calendar.getInstance();
		endTime.set(t.getTimeEnd().getYear(), t.getTimeEnd().getMonth(), t.getTimeEnd().getMonthDay(), t.getTimeEnd().getHour(), t.getTimeEnd().getMinute());
		endMillis = endTime.getTimeInMillis();

		ContentResolver cr = context.getContentResolver();
		ContentValues values = new ContentValues();
		Uri updateUri = null;
		// The new title for the event
		values.put(Events.TITLE, t.getName()); 
		values.put(Events.DESCRIPTION, t.getDescricao()); 
		values.put(Events.DTSTART, startMillis);
		values.put(Events.DTEND, endMillis);

		updateUri = ContentUris.withAppendedId(Events.CONTENT_URI, t.getGoogleCalendarID());
		int rows = cr.update(updateUri, values, null, null);
		if(rows !=0)
			return true;
		return false;
	}


	public static ArrayList<OccupiedBlocks> getOccupiedBlocks(Context context, KCGTDTime inicio_dia, KCGTDTime fim_dia){
		// event instances
		Calendar beginTime = Calendar.getInstance();
		beginTime.set(inicio_dia.getYear(), inicio_dia.getMonth(), inicio_dia.getMonthDay(), inicio_dia.getHour(), inicio_dia.getMinute());
		long startMillis = beginTime.getTimeInMillis();
		
		Calendar endTime = Calendar.getInstance();
		endTime.set(fim_dia.getYear(), fim_dia.getMonth(), fim_dia.getMonthDay(), fim_dia.getHour(), fim_dia.getMinute());
		long endMillis = endTime.getTimeInMillis();

		Cursor cur = null;
		ContentResolver cr = context.getContentResolver();

		// Construct the query with the desired date range.
		Uri.Builder builder = Instances.CONTENT_URI.buildUpon();
		ContentUris.appendId(builder, startMillis);
		ContentUris.appendId(builder, endMillis);

		// Submit the query
		cur =  cr.query(builder.build(), INSTANCE_PROJECTION, null, null, null);

		ArrayList<OccupiedBlocks> occupiedBlocks = new ArrayList<OccupiedBlocks>();
		
		while (cur.moveToNext()) {
			String title = null;
			@SuppressWarnings("unused")
			long eventID = 0;
			long beginVal = 0; 					
			long endVal = 0; 	
			String location = null;
			
			// Get the field values
			eventID = cur.getLong(PROJECTION_ID_INDEX);
			beginVal = cur.getLong(PROJECTION_BEGIN_INDEX);
			title = cur.getString(PROJECTION_TITLE_INDEX);
			endVal = cur.getLong(PROJECTION_END_INDEX);
			location = cur.getString(PROJECTION_EVENT_LOCATION);

			// Do something with the values. 
			KCGTDTime timeStart = new KCGTDTime();
			setTimeValues(beginVal, timeStart);

			KCGTDTime timeEnd = new KCGTDTime();
			setTimeValues(endVal, timeEnd);
			
			if(Utils.getDurationBetweenHours(timeStart, timeEnd).getMonthDay() < 1){
				//Localização do evento
				occupiedBlocks.add(new OccupiedBlocks(timeStart, timeEnd, title, location));
			}
			
		}
		
		return occupiedBlocks;
	}

	private static void setTimeValues(long value, KCGTDTime time) {
		Calendar calendar = Calendar.getInstance();
		calendar.setTimeInMillis(value); 
		
		time.setYear(calendar.get(Calendar.YEAR));
		time.setMonth(calendar.get(Calendar.MONTH));
		time.setMonthDay(calendar.get(Calendar.DAY_OF_MONTH));
		
		String date = Utils.FormatDateTime(calendar);
		
		time.setHour(Integer.valueOf(date.split(":")[0]));
		time.setMinute(Integer.valueOf(date.split(":")[1]));
	}

	public static ArrayList<FreeBlocks> getFreeCalendarSpaces(Context context, KCGTDTime time){

		Settings settings = MainActivity.settings;
		
		KCGTDTime currentTime = new KCGTDTime();
		KCGTDTime settingsInitialTime = new KCGTDTime(0, settings.getStartMinutes(), settings.getStartHour(), time.getMonthDay(), time.getMonth(), time.getYear()); 
		KCGTDTime inicio_dia;
//		boolean skipBlock = false;
		
		if(currentTime.isAfter(settingsInitialTime)){
			inicio_dia = new KCGTDTime(currentTime);
//			skipBlock = true;
		}else
			inicio_dia = new KCGTDTime(settingsInitialTime);
		
		KCGTDTime fim_dia = new KCGTDTime(0, settings.getEndMinutes(), settings.getEndHour(), time.getMonthDay(), time.getMonth(), time.getYear());
		
		ArrayList<OccupiedBlocks> occupiedBlocks = ProviderCalendar.getOccupiedBlocks(context, inicio_dia, fim_dia);
		Collections.sort(occupiedBlocks);
		ArrayList<FreeBlocks> freeBlocks = new ArrayList<FreeBlocks>();
		
		KCGTDTime start = inicio_dia; 
		KCGTDTime end;
		
		for (OccupiedBlocks cB : occupiedBlocks) {
			if(cB.getStartTime().isAfter(start) && moreThenOneMinute(cB.getStartTime(), start)){
				end = cB.getStartTime();
				
				freeBlocks.add(new FreeBlocks(start, end, cB));
				
				start = cB.getEndTime();
//				skipBlock = false;
			}else{
//				if(!skipBlock)
					start = cB.getEndTime();
			}
		}
		
		if(start.isBefore(fim_dia)){
			FreeBlocks f = new FreeBlocks(start, fim_dia, null);
			freeBlocks.add(f);
		}
		
		return freeBlocks;
	}
	
	private static boolean moreThenOneMinute(KCGTDTime s, KCGTDTime e){
		KCGTDTime t = Utils.getDurationBetweenHours(s, e);
		if(t.getHour() == 0 && t.getMinute() == 0)
			return false;
		else
			return true;
	}
	
}
